package com.zlm.config;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.zlm.filter.LoginFilter;
import com.zlm.service.MyUserDetailService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

/**
 * springsecurity配置类
 */


@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    // 使用自定义的数据源
    @Resource
    private MyUserDetailService myUserDetailService;

    /*@Bean
    public UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();
        userDetailsManager.createUser(User.withUsername("root").password("{noop}1234").roles("admin").build());
        return userDetailsManager;
    }*/

    // 自定义AuthenticationManager
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailService);
    }

    // 进行暴露
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    // 注入AuthenticationManager
    @Bean
    public LoginFilter loginFilter() throws Exception {
        LoginFilter loginFilter = new LoginFilter();
        // 还要指定一下认证的url
        loginFilter.setFilterProcessesUrl("/doLogin");
        loginFilter.setUsernameParameter("uname"); // 指定接受json
        loginFilter.setPasswordParameter("passwd");
        loginFilter.setAuthenticationManager(authenticationManagerBean());
        // 认证成功处理
        loginFilter.setAuthenticationSuccessHandler((req, resp, authentication) -> {
            Map<String, Object> result = new HashMap<>();
            result.put("message", "登录成功");
            resp.setStatus(HttpStatus.OK.value());
            result.put("authentication", authentication);
            String resultString = new ObjectMapper().writeValueAsString(result);
            resp.setContentType("application/json;charset=UTF-8");
            resp.getWriter().write(resultString);
        });

        // 认证失败处理
        loginFilter.setAuthenticationFailureHandler((req, resp, authenticationException) -> {
            Map<String, Object> result = new HashMap<>();
            result.put("message", "未认证");
            resp.setStatus(HttpStatus.INSUFFICIENT_STORAGE.value());
            result.put("authenticationException", authenticationException);
            String resultString = new ObjectMapper().writeValueAsString(result);
            resp.setContentType("application/json;charset=UTF-8");
            resp.getWriter().write(resultString);
        });
        return loginFilter;
    }

    /**
     * 这里的话就不能使用formLogin了因为底层是前后不分离的
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()
                .anyRequest().authenticated() // 所有请求必须认证
                .and()
                .formLogin()
                .and()
                .csrf().disable(); // csrf漏洞保护

        // at 用某个filter 替换过滤器链中哪个 filter  before: 放在哪个过滤器之前
        // after:放在哪个过滤器之后
        // 用loginFilter去替换userNamePasswordAuthenticationFilter
        http.addFilterAt(loginFilter(), UsernamePasswordAuthenticationFilter.class);
    }
}
